/**
 * @author DongPing
 * 2022/1/25 14:08
 *
 * 订阅数据变化的工具
 * 当某些数据需要和组件的状态绑定的时候，可以使用这个工具。组件通过事件订阅的方式订阅数据的变化，
 * 然后更新组件
 *
 * */
import {useEffect, useState} from "react";

export class Subscribable<T> {
	//  被管理的数据
	private _current: T;
	get current() {
		return this._current;
	}
	set current(value: T) {
		this._current = value;
		this.dispatch();
	}

	constructor(initialValue: T) {
		this._current = initialValue;
		this.callbacks = [];

		this.subscribe = this.subscribe.bind(this);
		this.unsubscribe = this.unsubscribe.bind(this);
	}

	/**
	 * 监听数据的回调函数
	 * */
	private callbacks: Array<(value: T) => void>;

	/**
	 * 添加监听回调
	 * */
	subscribe(callback: (value: T) => void) {
		this.callbacks.push(callback);
	}
	/**
	 * 取消监听
	 * */
	unsubscribe(callback: (value: T) => void) {
		this.callbacks = this.callbacks.filter((item) => item !== callback);
	}

	/**
	 * 数据变化，分发事件
	 * */
	private dispatch() {
		for(const callback of this.callbacks) {
			callback(this._current);
		}
	}
}

/**
 * 使用可订阅数据 的 hook
 * 可用于function Component ，监听某个数据的变化，更新组件
 * */
export function useSubscribable<T>(subscribable: Subscribable<T>): T {
	const [data, setData] = useState<T>(subscribable.current);
	useEffect(function () {
		subscribable.subscribe(setData);
		return function () {
			subscribable.unsubscribe(setData);
		}
	}, []);
	return data;
}
